/**
 * @file:          FlashManager.c
 * @brief:
 * @details:
 * @author:        wjh
 * @date created:  2023.08.22
 * @version:       1.0.0
 * @par copyright (c):
 *
 * @par history (desc):
 *   version:1.0.0, wjh, 2023.08.22,16:05:20
 */

/* Include Files **************************************************************/
#include "FlashManager.h"
#include "string.h"
#include "stdlib.h"

/* Global Variable Define *****************************************************/
DataConversion data_conversion;

/* Function Define ************************************************************/

void FlashManager_Init(struct FlashManager *self)
{
    self->RegisterVariableToTable = FlashManager_RegisterVariableToTable;
    self->SaveVariableIntoFlash = FlashManager_SaveVariableIntoFlash;
    self->LoadVariableFromFlash = FlashManager_LoadVariableFromFlash;
    self->SaveAllVariableIntoFlash = FlashManager_SaveAllVariableIntoFlash;
    self->LoadAllVariableFromFlash = FlashManager_LoadAllVariableFromFlash;
    self->ListVariableOfSystem = FlashManager_ListVariableOfSystem;
    self->ListAllVariableOfSystem = FlashManager_ListAllVariableOfSystem;
    self->WriteVariableIntoFlash = FlashManager_WriteVariableIntoFlash;
    self->ReadVariableFromFlash = FlashManager_ReadVariableFromFlash;
    self->ReadAllVariableFromFlash = FlashManager_ReadAllVariableFromFlash;
    // self->ReadAllVariableFromFlashAsync_Trigger = FlashManager_ReadAllVariableFromFlashAsync_Trigger;
    // self->ReadAllVariableFromFlashAsync_Task = FlashManager_ReadAllVariableFromFlashAsync_Task;
    self->ListAllVariableOfSystemAsync_Trigger = FlashManager_ListAllVariableOfSystemAsync_Trigger;
    self->ListAllVariableOfSystemAsync_Task = FlashManager_ListAllVariableOfSystemAsync_Task;
    self->Async_Task = FlashManager_Async_Task;
    self->VariableIsExist = FlashManager_VariableIsExist;
    self->DataSolution = FlashManager_DataSolution;
    self->CheckAllDataValid = FlashManager_CheckAllDataValid;
    self->EraseAll = FlashManager_EraseAll;
    self->SaveAllBase = FlashManager_SaveAllBase;
    self->EraseSectionOfVariable = FlashManager_EraseSectionOfVariable;
    self->SaveSectionOfVariable = FlashManager_SaveSectionOfVariable;

    self->flash_end_addr = self->param_flash_start_addr + self->param_flash_size_byte;
}

void FlashManager_RegisterVariableToTable(struct FlashManager *self, uint16_t data_num, uint8_t reboot_to_take_effect, void *data_addr, uint8_t data_bytes, char *data_type, char *name)
{
    self->data_table[data_num].addr = data_addr;
    self->data_table[data_num].bytes = data_bytes;
    self->data_table[data_num].type = data_type;
    self->data_table[data_num].name = name;
    self->data_table[data_num].reboot_to_take_effect = reboot_to_take_effect;
    self->data_nums++;
    self->data_total_bytes += data_bytes;
    if (data_num > self->data_max_num)
    {
        self->data_max_num = data_num;
    }
}

uint8_t FlashManager_SaveVariableIntoFlash(struct FlashManager *self, char *name)
{
    uint8_t success = 1;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;
    DataConversion flash_value_old;
    DataConversion sys_value_new;

    // self->mcu->sysclk_hz = self->mcu->param_sysclk_hz_for_flash_operation;
    // self->mcu->InitClock(self->mcu);
    // self->mcu->InitDelay(self->mcu);
    self->mcu->HCLKSetToDiv2();

    // self->EraseAll(self);
    self->EraseSectionOfVariable(self, name);

    // self->mcu->DelayMs(self->mcu, 100);
    // self->mcu->FlashUnlock();
    // success = FlashManager_SaveAllBase(self);
    success = self->SaveSectionOfVariable(self, name);
    // self->mcu->FlashLock();

    // self->mcu->sysclk_hz = self->mcu->param_sysclk_hz;
    // self->mcu->InitClock(self->mcu);
    // self->mcu->InitDelay(self->mcu);
    self->mcu->HCLKSetToDiv1();

    // if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    // {
    //     // success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");

    //     if (strcmp(self->data_table[index].type, "uint16_t") == 0 ||
    //         strcmp(self->data_table[index].type, "int16_t") == 0)
    //     {
    //         /* now sys value */
    //         sys_value_new.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);

    //         /* old flash value */
    //         self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
    //         flash_value_old.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);

    //         /* write now sys value into flash */
    //         if (strcmp(self->data_table[index].type, "uint16_t") == 0)
    //         {
    //             *(volatile uint16_t *)(self->data_table[index].addr) = sys_value_new.u16[0];
    //         }
    //         else if (strcmp(self->data_table[index].type, "int16_t") == 0)
    //         {
    //             *(volatile int16_t *)(self->data_table[index].addr) = sys_value_new.s16[0];
    //         }
    //         self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");

    //         /* check if write ok */
    //         self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");

    //         if (sys_value_new.u16[0] != *(volatile uint16_t *)(self->data_table[index].addr))
    //         {
    //             success = 0;
    //         }

    //         self->flash_checksum += sys_value_new.u16[0] - flash_value_old.u16[0];
    //     }
    //     else if (strcmp(self->data_table[index].type, "uint32_t") == 0 ||
    //              strcmp(self->data_table[index].type, "int32_t") == 0 ||
    //              strcmp(self->data_table[index].type, "float") == 0)
    //     {
    //         /* now sys value */
    //         sys_value_new.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);
    //         sys_value_new.u16[1] = *(volatile uint16_t *)(self->data_table[index].addr + 2);

    //         /* old flash value */
    //         self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
    //         flash_value_old.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);
    //         flash_value_old.u16[1] = *(volatile uint16_t *)(self->data_table[index].addr + 2);

    //         /* write now sys value into flash */
    //         if (strcmp(self->data_table[index].type, "uint32_t") == 0)
    //         {
    //             *(volatile uint32_t *)(self->data_table[index].addr) = sys_value_new.u32;
    //         }
    //         else if (strcmp(self->data_table[index].type, "int32_t") == 0)
    //         {
    //             *(volatile int32_t *)(self->data_table[index].addr) = sys_value_new.s32;
    //         }
    //         else if (strcmp(self->data_table[index].type, "float") == 0)
    //         {
    //             *(volatile float *)(self->data_table[index].addr) = sys_value_new.f32;
    //         }
    //         self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");

    //         /* check if write ok */
    //         self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
    //         if (sys_value_new.u16[0] != *(volatile uint16_t *)(self->data_table[index].addr) ||
    //             sys_value_new.u16[1] != *(volatile uint16_t *)(self->data_table[index].addr + 2))
    //         {
    //             success = 0;
    //         }
    //         self->flash_checksum += sys_value_new.u16[0] + sys_value_new.u16[1] - flash_value_old.u16[0] - flash_value_old.u16[1];
    //     }
    // }

    // if (self->VariableIsExist(self, "flash_checksum", &index, &bytes_sum_before_dat) == 1)
    // {
    //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");
    // }
#endif
    return success;
}

uint8_t FlashManager_LoadVariableFromFlash(struct FlashManager *self, char *name)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    {
        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
    }

#endif
    return success;
}

uint8_t FlashManager_SaveAllVariableIntoFlash(struct FlashManager *self)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE
    // self->mcu->sysclk_hz = self->mcu->param_sysclk_hz_for_flash_operation;
    // self->mcu->InitClock(self->mcu);
    // self->mcu->InitDelay(self->mcu);
    self->mcu->HCLKSetToDiv2();

    // DISABLE_GLOBAL_INTERRUPT();
    self->EraseAll(self);

    // self->mcu->DelayMs(self->mcu, 100);
    // self->mcu->FlashUnlock();
    success = self->SaveAllBase(self);
    // self->mcu->FlashLock();

    // self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
    // ENABLE_GLOBAL_INTERRUPT();

    // self->mcu->sysclk_hz = self->mcu->param_sysclk_hz;
    // self->mcu->InitClock(self->mcu);
    // self->mcu->InitDelay(self->mcu);
    self->mcu->HCLKSetToDiv1();

#endif
    return success;
}

uint8_t FlashManager_LoadAllVariableFromFlash(struct FlashManager *self)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE

    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    for (index = 0; index <= self->data_max_num; index++)
    {
        if (self->data_table[index].addr == NULL)
        {
            continue;
        }

        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
        bytes_sum_before_dat += self->data_table[index].bytes;
    }
#endif
    return success;
}

uint8_t FlashManager_ListVariableOfSystem(struct FlashManager *self, char *name)
{
    uint8_t success = 0;

    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    {
        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_List, "");
    }

    return success;
}

uint8_t FlashManager_ListAllVariableOfSystem(struct FlashManager *self)
{
    uint8_t success = 0;

    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    TERMINAL_AdvStr("\r\n");
    for (index = 0; index <= self->data_max_num; index++)
    {
        if (self->data_table[index].addr == NULL)
        {
            continue;
        }

        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_List, "");
        bytes_sum_before_dat += self->data_table[index].bytes;
    }

    return success;
}

uint8_t FlashManager_WriteVariableIntoFlash(struct FlashManager *self, char *name, char *data_str)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;
    DataConversion flash_value_old;
    DataConversion flash_value_new;
    DataConversion sys_value_new;

    // self->mcu->sysclk_hz = self->mcu->param_sysclk_hz_for_flash_operation;
    // self->mcu->InitClock(self->mcu);
    // self->mcu->InitDelay(self->mcu);
    self->mcu->HCLKSetToDiv2();

    // self->EraseAll(self);
    self->EraseSectionOfVariable(self, name);

    // self->mcu->DelayMs(self->mcu, 100);
    // self->mcu->FlashUnlock();
    self->out_reboot_to_take_effect = FlashParam_RebootToTakeEffect_No;
    if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    {
        self->out_reboot_to_take_effect = self->data_table[index].reboot_to_take_effect;

        // success = 1;
        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Write, data_str);

        // if (strcmp(self->data_table[index].type, "uint16_t") == 0 ||
        //     strcmp(self->data_table[index].type, "int16_t") == 0)
        // {
        //     /* old flash value */
        //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
        //     flash_value_old.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);

        //     /* new flash value */
        //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Write, data_str);
        //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Read, (void *)(&flash_value_new.u32));

        //     /* new sys value */

        //     /* write now sys value into flash */
        //     if (strcmp(self->data_table[index].type, "uint16_t") == 0)
        //     {
        //         sys_value_new.u16[0] = (uint16_t)atoi((char *)data_str);
        //     }
        //     else if (strcmp(self->data_table[index].type, "int16_t") == 0)
        //     {
        //         sys_value_new.s16[0] = (int16_t)atoi((char *)data_str);
        //     }

        //     /* check if write ok */
        //     if (sys_value_new.u16[0] != flash_value_new.s16[0])
        //     {
        //         success = 0;
        //     }
        //     // self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");

        //     self->flash_checksum += flash_value_new.u16[0] - flash_value_old.u16[0];
        // }
        // else if (strcmp(self->data_table[index].type, "uint32_t") == 0 ||
        //          strcmp(self->data_table[index].type, "int32_t") == 0 ||
        //          strcmp(self->data_table[index].type, "float") == 0)
        // {
        //     /* old flash value */
        //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
        //     flash_value_old.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);
        //     flash_value_old.u16[1] = *(volatile uint16_t *)(self->data_table[index].addr + 2);

        //     /* new flash value */
        //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Write, data_str);
        //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Read, (void *)(&flash_value_new.u32));

        //     /* write now sys value into flash */
        //     if (strcmp(self->data_table[index].type, "uint32_t") == 0)
        //     {
        //         sys_value_new.u32 = (uint32_t)atol((char *)data_str);
        //     }
        //     else if (strcmp(self->data_table[index].type, "int32_t") == 0)
        //     {
        //         sys_value_new.s32 = (int32_t)atol((char *)data_str);
        //     }
        //     else if (strcmp(self->data_table[index].type, "float") == 0)
        //     {
        //         sys_value_new.f32 = (float)atof((char *)data_str);
        //     }

        //     /* check if write ok */
        //     if (sys_value_new.u16[0] != flash_value_new.s16[0] ||
        //         sys_value_new.u16[1] != flash_value_new.s16[1])
        //     {
        //         success = 0;
        //     }
        //     // self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");

        //     self->flash_checksum += flash_value_new.u16[0] + flash_value_new.u16[1] - flash_value_old.u16[0] - flash_value_old.u16[1];
        // }
        // else
        // {
        //     success = 0;
        // }
    }

    // if (self->VariableIsExist(self, "flash_checksum", &index, &bytes_sum_before_dat) == 1)
    // {
    //     self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");
    // }

    self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
    // FlashManager_SaveAllBase(self);
    self->SaveSectionOfVariable(self, name);

    // self->mcu->FlashLock();

    // self->mcu->sysclk_hz = self->mcu->param_sysclk_hz;
    // self->mcu->InitClock(self->mcu);
    // self->mcu->InitDelay(self->mcu);
    self->mcu->HCLKSetToDiv1();

#endif
    return success;
}

uint8_t FlashManager_ReadVariableFromFlash(struct FlashManager *self, char *name)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    {
        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Read, (void *)(&data_conversion.u32));
    }

#endif
    return success;
}

uint8_t FlashManager_ReadAllVariableFromFlash(struct FlashManager *self)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    TERMINAL_AdvStr("\r\n");
    for (index = 0; index <= self->data_max_num; index++)
    {
        if (self->data_table[index].addr == NULL)
        {
            continue;
        }

        success = self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Read, (void *)(&data_conversion.u32));
        bytes_sum_before_dat += self->data_table[index].bytes;
    }

#endif
    return success;
}

void FlashManager_ReadAllVariableFromFlashAsync_Trigger(struct FlashManager *self)
{
    self->async_read_trigger = 1;
    self->async_read_index = 0;
    self->async_read_bytes_sum = 0;
    TERMINAL_AdvStr("\r\n");
}

void FlashManager_ReadAllVariableFromFlashAsync_Task(struct FlashManager *self)
{
#ifndef HARDWARE_DISABLE

    if (self->async_read_trigger == 1)
    {
        while (self->data_table[self->async_read_index].addr == NULL && self->async_read_index <= self->data_max_num)
        {
            self->async_read_index++;
        }

        if (self->async_read_index <= self->data_max_num)
        {

            self->DataSolution(self, self->data_table[self->async_read_index], self->async_read_bytes_sum, DataSolutionMethod_Read, (void *)(&data_conversion.u32));
            self->async_read_bytes_sum += self->data_table[self->async_read_index].bytes;

            if (self->async_read_index < self->data_max_num)
            {
                self->async_read_index++;
            }
            else
            {
                self->async_read_trigger = 0;
            }
        }
        else
        {
            self->async_read_trigger = 0;
        }
    }

#endif
}

void FlashManager_ListAllVariableOfSystemAsync_Trigger(struct FlashManager *self)
{
    self->async_list_trigger = 1;
    self->async_list_index = 0;
    self->async_list_bytes_sum = 0;
    TERMINAL_AdvStr("\r\n");
}

void FlashManager_ListAllVariableOfSystemAsync_Task(struct FlashManager *self)
{
#ifndef HARDWARE_DISABLE
    static uint16_t count = 0;

    if (self->async_list_trigger == 1)
    {
        if (self->async_list_index == 0 && count == 0)
        {
            TERMINAL_Adv("[Total_nums]: %d\r\n", self->data_nums);
        }

        while (self->data_table[self->async_list_index].addr == NULL && self->async_list_index <= self->data_max_num)
        {
            self->async_list_index++;
        }

        if (count == 0)
        {
            if (self->async_list_index <= self->data_max_num)
            {

                self->DataSolution(self, self->data_table[self->async_list_index], self->async_list_bytes_sum, DataSolutionMethod_List, "");
                self->async_list_bytes_sum += self->data_table[self->async_list_index].bytes;

                if (self->async_list_index < self->data_max_num)
                {
                    self->async_list_index++;
                }
                else
                {
                    self->async_list_trigger = 0;
                    count = 1;
                }
            }
            else
            {
                self->async_list_trigger = 0;
                count = 1;
            }
        }
        count = (count + 1) % 50;
    }

#endif
}

void FlashManager_Async_Task(struct FlashManager *self)
{
    // self->ReadAllVariableFromFlashAsync_Task(self);
    self->ListAllVariableOfSystemAsync_Task(self);
}

uint8_t FlashManager_VariableIsExist(struct FlashManager *self, char *name, uint16_t *index, uint32_t *bytes_sum_before_dat)
{
    uint8_t exist = 0;

    *bytes_sum_before_dat = 0;
    for (*index = 0; *index <= self->data_max_num; (*index)++)
    {
        if (self->data_table[*index].addr == NULL)
        {
            continue;
        }

        if (strcmp(self->data_table[*index].name, name) == 0)
        {
            exist = 1;
            break;
        }
        *bytes_sum_before_dat += self->data_table[*index].bytes;
    }

    return exist;
}

uint8_t FlashManager_DataSolution(struct FlashManager *self, DataUnit dat, uint32_t bytes_sum_before_dat, enum DataSolutionMethod data_solution, void *data)
{
    uint8_t success = 0;
    DataTypeTranformer dtt;

    if (strcmp(dat.type, "uint16_t") == 0)
    {
        for (uint8_t i = 0; i < dat.bytes; i += (uint8_t)sizeof(uint16_t))
        {
            switch (data_solution)
            {
            case DataSolutionMethod_Save:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.u16[0] = *((volatile uint16_t *)(dat.addr + i));
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Load:
                *((volatile uint16_t *)(dat.addr + i)) = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                break;
            case DataSolutionMethod_List:
                TERMINAL_AdvStr(dat.name);
                TERMINAL_Adv(": %u\r\n", *(volatile uint16_t *)(dat.addr + i));
                break;
            case DataSolutionMethod_Write:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.u16[0] = (uint16_t)atoi((char *)data);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Read:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                *((volatile uint16_t *)data) = dtt.u16[0];
                // TERMINAL_AdvStr(dat.name);
                // TERMINAL_Adv(": %u\r\n", dtt.u16[0]);
                break;
            default:
                break;
            }
        }
    }
    else if (strcmp(dat.type, "int16_t") == 0)
    {
        for (uint8_t i = 0; i < dat.bytes; i += (uint8_t)sizeof(int16_t))
        {
            switch (data_solution)
            {
            case DataSolutionMethod_Save:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.u16[0] = *((volatile int16_t *)(dat.addr + i));
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Load:
                *((volatile int16_t *)(dat.addr + i)) = *((volatile int16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                break;
            case DataSolutionMethod_List:
                TERMINAL_AdvStr(dat.name);
                TERMINAL_Adv(": %d\r\n", *(volatile int16_t *)(dat.addr + i));
                break;
            case DataSolutionMethod_Write:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.u16[0] = (int16_t)atoi((char *)data);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Read:
                dtt.u16[0] = *((volatile int16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                *((volatile int16_t *)data) = dtt.s16[0];
                // TERMINAL_AdvStr(dat.name);
                // TERMINAL_Adv(": %d\r\n", dtt.s16[0]);
                break;
            default:
                break;
            }
        }
    }
    else if (strcmp(dat.type, "uint32_t") == 0)
    {
        for (uint8_t i = 0; i < dat.bytes; i += (uint8_t)sizeof(uint32_t))
        {
            switch (data_solution)
            {
            case DataSolutionMethod_Save:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.u32 = *((volatile uint32_t *)(dat.addr + i));
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i + 2,
                                              dtt.u16[1]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Load:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                dtt.u16[1] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i + 2));
                *((volatile uint32_t *)(dat.addr + i)) = dtt.u32;
                // *((volatile uint32_t *)(dat.addr + i)) = *((volatile uint32_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                break;
            case DataSolutionMethod_List:
                TERMINAL_AdvStr(dat.name);
                TERMINAL_Adv(": %lu\r\n", *(volatile uint32_t *)(dat.addr + i));
                break;
            case DataSolutionMethod_Write:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.u32 = (uint32_t)atol((char *)data);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i + 2,
                                              dtt.u16[1]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Read:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                dtt.u16[1] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i + 2));
                *((volatile uint32_t *)data) = dtt.u32;
                // TERMINAL_AdvStr(dat.name);
                // TERMINAL_Adv(": %lu\r\n", dtt.u32);
                break;
            default:
                break;
            }
        }
    }
    else if (strcmp(dat.type, "int32_t") == 0)
    {
        for (uint8_t i = 0; i < dat.bytes; i += (uint8_t)sizeof(int32_t))
        {
            switch (data_solution)
            {
            case DataSolutionMethod_Save:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.s32 = *((volatile int32_t *)(dat.addr + i));
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i + 2,
                                              dtt.u16[1]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Load:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                dtt.u16[1] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i + 2));
                *((volatile int32_t *)(dat.addr + i)) = dtt.s32;
                // *((volatile int32_t *)(dat.addr + i)) = *((volatile int32_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                break;
            case DataSolutionMethod_List:
                TERMINAL_AdvStr(dat.name);
                TERMINAL_Adv(": %ld\r\n", *(volatile int32_t *)(dat.addr + i));
                break;
            case DataSolutionMethod_Write:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.s32 = (int32_t)atol((char *)data);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i + 2,
                                              dtt.u16[1]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Read:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                dtt.u16[1] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i + 2));
                *((volatile int32_t *)data) = dtt.s32;
                // TERMINAL_AdvStr(dat.name);
                // TERMINAL_Adv(": %ld\r\n", dtt.s32);
                break;
            default:
                break;
            }
        }
    }
    else if (strcmp(dat.type, "float") == 0)
    {
        for (uint8_t i = 0; i < dat.bytes; i += (uint8_t)sizeof(float))
        {
            switch (data_solution)
            {
            case DataSolutionMethod_Save:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.f32 = *((volatile float *)(dat.addr + i));
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i + 2,
                                              dtt.u16[1]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Load:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                dtt.u16[1] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i + 2));
                *((volatile float *)(dat.addr + i)) = dtt.f32;
                // *((volatile float *)(dat.addr + i)) = *((volatile float *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                break;
            case DataSolutionMethod_List:
                TERMINAL_AdvStr(dat.name);
                if (*(volatile float *)(dat.addr + i) >= 1 || *(volatile float *)(dat.addr + i) == 0)
                {
                    TERMINAL_Adv(": %s\r\n", float2str(*(volatile float *)(dat.addr + i), 1));
                }
                else
                {
                    TERMINAL_Adv(": %s\r\n", float2str(*(volatile float *)(dat.addr + i), 6));
                }
                // float tmp = *(volatile float *)(dat.addr + i);
                // TERMINAL_Adv(": %ld.%ld\r\n", (int32_t)(tmp), (int32_t)(tmp * FLOAT_DISP_MASK) % FLOAT_DISP_MASK);
                break;
            case DataSolutionMethod_Write:
                DISABLE_GLOBAL_INTERRUPT();
                self->mcu->FlashUnlock();

                dtt.f32 = (float)atof((char *)data);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i,
                                              dtt.u16[0]);
                self->mcu->FlashWriteHalfWord((uint32)self->param_flash_start_addr,
                                              bytes_sum_before_dat + i + 2,
                                              dtt.u16[1]);

                self->mcu->FlashLock();
                self->mcu->DelayMs(self->mcu, FLASH_MANAGER_WRITE_DELAY_MS);
                ENABLE_GLOBAL_INTERRUPT();
                break;
            case DataSolutionMethod_Read:
                dtt.u16[0] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i));
                dtt.u16[1] = *((volatile uint16_t *)(self->param_flash_start_addr + bytes_sum_before_dat + i + 2));
                // TERMINAL_Adv(": %ld.%ld\r\n", (int32_t)(dtt.f32), (int32_t)(dtt.f32 * FLOAT_DISP_MASK) % FLOAT_DISP_MASK);

                *((volatile float *)data) = dtt.f32;

                // TERMINAL_AdvStr(dat.name);
                // if (dtt.f32 >= 1 || dtt.f32 == 0)
                // {
                //     TERMINAL_Adv(": %s\r\n", float2str(dtt.f32, 1));
                // }
                // else
                // {
                //     TERMINAL_Adv(": %s\r\n", float2str(dtt.f32, 4));
                // }
                break;
            default:
                break;
            }
        }
    }

    return success;
}

uint8_t FlashManager_CheckAllDataValid(struct FlashManager *self)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;
    uint16_t flash_checksum;

    self->checksum = 0;
    for (index = 0; index <= self->data_max_num; index++)
    {
        if (self->data_table[index].addr == NULL)
        {
            continue;
        }

        self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Read, (void *)(&data_conversion.u32));

        if (index == self->data_max_num) /* The last position data is flash_checksum */
        {
            flash_checksum = data_conversion.u16[0];
            // DBprintf("===\r\n");
            // DBprintf("%s: %d\r\n", self->data_table[index].name, *((volatile uint16_t *)self->data_table[index].addr));
            if (self->checksum == flash_checksum)
            {
                success = 1;
            }
        }
        else
        {
            if (strcmp(self->data_table[index].type, "uint16_t") == 0)
            {
                self->checksum += data_conversion.u16[0];
            }
            else if (strcmp(self->data_table[index].type, "int16_t") == 0)
            {
                self->checksum += data_conversion.s16[0];
            }
            else if (strcmp(self->data_table[index].type, "uint32_t") == 0)
            {
                self->checksum += data_conversion.u16[0];
                self->checksum += data_conversion.u16[1];
            }
            else if (strcmp(self->data_table[index].type, "int32_t") == 0)
            {
                self->checksum += data_conversion.u16[0];
                self->checksum += data_conversion.u16[1];
            }
            else if (strcmp(self->data_table[index].type, "float") == 0)
            {
                self->checksum += data_conversion.u16[0];
                self->checksum += data_conversion.u16[1];
            }
        }

        bytes_sum_before_dat += self->data_table[index].bytes;
    }

#endif
    return success;
}

uint8_t FlashManager_EraseAll(struct FlashManager *self)
{
    DISABLE_GLOBAL_INTERRUPT();
    self->mcu->FlashUnlockFast();
    for (uint16_t i = 0; i < self->param_flash_size_byte / 256; i++)
    {
        self->mcu->FlashEraseOnePage256Bytes_Fast(self->param_flash_start_addr, i);
    }
    self->mcu->FlashLockFast();
    self->mcu->DelayMs(self->mcu, 1000);
    ENABLE_GLOBAL_INTERRUPT();
}

uint8_t FlashManager_SaveAllBase(struct FlashManager *self)
{
    uint8_t success = 0;
#ifndef HARDWARE_DISABLE

    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    self->checksum = 0;
    for (index = 0; index <= self->data_max_num; index++)
    {
        if (self->data_table[index].addr == NULL)
        {
            continue;
        }

        success = 1;

        /* check if write ok */
        if (index == self->data_max_num) /* The last position data is flash_checksum */
        {
            self->flash_checksum = self->checksum;
            self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");
        }
        else
        {
            self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");

            if (strcmp(self->data_table[index].type, "uint16_t") == 0 ||
                strcmp(self->data_table[index].type, "int16_t") == 0)
            {
                data_conversion.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);
                self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
                if (data_conversion.u16[0] != *(volatile uint16_t *)(self->data_table[index].addr))
                {
                    success = 0;
                    // break;
                }

                *(volatile uint16_t *)(self->data_table[index].addr) = data_conversion.u16[0];
                self->checksum += data_conversion.u16[0];
            }
            else if (strcmp(self->data_table[index].type, "uint32_t") == 0 ||
                     strcmp(self->data_table[index].type, "int32_t") == 0 ||
                     strcmp(self->data_table[index].type, "float") == 0)
            {
                data_conversion.u16[0] = *(volatile uint16_t *)(self->data_table[index].addr);
                data_conversion.u16[1] = *(volatile uint16_t *)(self->data_table[index].addr + 2);
                self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Load, "");
                if (data_conversion.u16[0] != *(volatile uint16_t *)(self->data_table[index].addr) ||
                    data_conversion.u16[1] != *(volatile uint16_t *)(self->data_table[index].addr + 2))
                {
                    success = 0;
                    // break;
                }

                *(volatile uint16_t *)(self->data_table[index].addr) = data_conversion.u16[0];
                *(volatile uint16_t *)(self->data_table[index].addr + 2) = data_conversion.u16[1];
                self->checksum += data_conversion.u16[0];
                self->checksum += data_conversion.u16[1];
            }
        }
        bytes_sum_before_dat += self->data_table[index].bytes;
    }
    if (success == 0)
    {
        DBprintf("suc: %d\r\n", success);
        DBprintf("Err data: [%d]: %s | %s\r\n", index, self->data_table[index].name, self->data_table[index].type);
        DBprintf("sys value: %d, %d\r\n", *(volatile uint16_t *)(self->data_table[index].addr), *(volatile uint16_t *)(self->data_table[index].addr + 2));
        DBprintf("flash value: %d, %d\r\n", data_conversion.u16[0], data_conversion.u16[1]);
    }

#endif
    return success;
}

uint8_t FlashManager_EraseSectionOfVariable(struct FlashManager *self, char *name)
{
    uint8_t success = 1;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;

    if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    {
        uint16_t m = bytes_sum_before_dat / 256;
        uint16_t n = (bytes_sum_before_dat + self->data_table[index].bytes) / 256;

        DISABLE_GLOBAL_INTERRUPT();
        self->mcu->FlashUnlockFast();
        self->mcu->FlashEraseOnePage256Bytes_Fast(self->param_flash_start_addr, m);
        if (m != n)
        {
            self->mcu->FlashEraseOnePage256Bytes_Fast(self->param_flash_start_addr, n);
        }
        self->mcu->FlashLockFast();
        self->mcu->DelayMs(self->mcu, 1000);
        ENABLE_GLOBAL_INTERRUPT();
    }
#endif
    return success;
}

uint8_t FlashManager_SaveSectionOfVariable(struct FlashManager *self, char *name)
{
    uint8_t success = 1;
#ifndef HARDWARE_DISABLE
    uint16_t index;
    uint32_t bytes_sum_before_dat = 0;
    uint16_t m, n;

    if (self->VariableIsExist(self, name, &index, &bytes_sum_before_dat) == 1)
    {
        m = bytes_sum_before_dat / 256;
        n = (bytes_sum_before_dat + self->data_table[index].bytes) / 256;
    }

    bytes_sum_before_dat = 0;
    for (index = 0; index <= self->data_max_num; index++)
    {
        if (self->data_table[index].addr == NULL)
        {
            continue;
        }

        if (bytes_sum_before_dat / 256 == m ||
            bytes_sum_before_dat / 256 == n)
        {
            self->DataSolution(self, self->data_table[index], bytes_sum_before_dat, DataSolutionMethod_Save, "");
        }

        bytes_sum_before_dat += self->data_table[index].bytes;
    }

#endif
    return success;
}